import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'dart:async';

// 自定义错误类型
class DataSyncException implements Exception {
  final String message;
  final DataSyncErrorType type;
  final dynamic originalError;

  DataSyncException(this.message, this.type, [this.originalError]);

  @override
  String toString() => 'DataSyncException: $message (Type: $type)';
}

enum DataSyncErrorType {
  networkError, // 网络连接错误
  authenticationError, // 认证错误
  dataValidationError, // 数据验证错误
  serverError, // 服务器错误
  localStorageError, // 本地存储错误
  unknownError, // 未知错误
}

class DataSyncService {
  static const String _baseUrl = 'https://api.github.com';
  static const String _repoPath =
      '/repos/silence-3013/fin-track-data/contents/data';
  static const String _tokenKey = 'github_token';

  final SharedPreferences _prefs;
  late final Dio _dio;
  final Connectivity _connectivity = Connectivity();

  // 添加数据监测相关属性
  DateTime? _lastDataCheck;
  Map<String, dynamic>? _lastDataSnapshot;
  bool _isMonitoring = false;
  Timer? _monitoringTimer;

  // 获取监测状态
  bool get isMonitoring => _isMonitoring;
  DateTime? get lastDataCheck => _lastDataCheck;

  // 设置 GitHub Token
  Future<void> setGitHubToken(String token) async {
    await _prefs.setString(_tokenKey, token);
    _updateDioHeaders(token);
  }

  // 获取 GitHub Token
  String? getGitHubToken() {
    return _prefs.getString(_tokenKey);
  }

  // 更新 Dio 的 headers
  void _updateDioHeaders(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }

  // 开始数据监测
  void startMonitoring({Duration interval = const Duration(minutes: 5)}) {
    if (_isMonitoring) return;

    _isMonitoring = true;
    _monitoringTimer = Timer.periodic(interval, (_) async {
      await checkDataChanges();
    });
  }

  // 停止数据监测
  void stopMonitoring() {
    _isMonitoring = false;
    _monitoringTimer?.cancel();
    _monitoringTimer = null;
  }

  // 检查数据变化
  Future<bool> checkDataChanges() async {
    try {
      _lastDataCheck = DateTime.now();
      final currentData = await fetchDataFromGitHub();

      if (_lastDataSnapshot == null) {
        _lastDataSnapshot = currentData;
        return false;
      }

      final hasChanges = !mapEquals(_lastDataSnapshot, currentData);
      _lastDataSnapshot = currentData;

      return hasChanges;
    } catch (e) {
      debugPrint('检查数据变化时出错: $e');
      return false;
    }
  }

  // 获取数据统计信息
  Future<Map<String, dynamic>> getDataStats() async {
    try {
      final data = await fetchDataFromGitHub();
      if (data['transactions'] is! List) {
        return {'totalTransactions': 0, 'lastUpdate': null, 'error': '数据格式错误'};
      }

      final transactions = data['transactions'] as List;
      return {
        'totalTransactions': transactions.length,
        'lastUpdate': data['lastSync'],
        'error': null,
      };
    } catch (e) {
      return {
        'totalTransactions': 0,
        'lastUpdate': null,
        'error': e.toString(),
      };
    }
  }

  DataSyncService(this._prefs) {
    _dio = Dio(
        BaseOptions(
          baseUrl: _baseUrl,
          headers: {'Accept': 'application/vnd.github.v3+json'},
          connectTimeout: const Duration(seconds: 30),
          receiveTimeout: const Duration(seconds: 30),
          sendTimeout: const Duration(seconds: 30),
          validateStatus: (status) => status! < 500,
        ),
      )
      ..httpClientAdapter = IOHttpClientAdapter(
        createHttpClient: () {
          final client = HttpClient();
          client.badCertificateCallback =
              (X509Certificate cert, String host, int port) => true;
          return client;
        },
      );

    // 如果有保存的 token，设置到 headers 中
    final savedToken = getGitHubToken();
    if (savedToken != null) {
      _updateDioHeaders(savedToken);
    }

    // 添加重试拦截器
    _dio.interceptors.add(
      InterceptorsWrapper(
        onError: (DioException e, ErrorInterceptorHandler handler) async {
          debugPrint('网络请求错误: ${e.type} - ${e.message}');

          // 检查网络连接
          final connectivityResult = await _connectivity.checkConnectivity();
          if (connectivityResult == ConnectivityResult.none) {
            return handler.next(e);
          }

          // 处理不同类型的错误
          if (e.type == DioExceptionType.connectionTimeout ||
              e.type == DioExceptionType.receiveTimeout ||
              e.type == DioExceptionType.sendTimeout ||
              e.type == DioExceptionType.connectionError) {
            // 重试3次
            for (int i = 0; i < 3; i++) {
              try {
                debugPrint('尝试重试请求 (${i + 1}/3)');
                final response = await _dio.request(
                  e.requestOptions.path,
                  data: e.requestOptions.data,
                  queryParameters: e.requestOptions.queryParameters,
                  options: Options(
                    method: e.requestOptions.method,
                    headers: e.requestOptions.headers,
                  ),
                );
                return handler.resolve(response);
              } catch (retryError) {
                debugPrint('重试失败: $retryError');
                if (i == 2) {
                  if (retryError is DioException) {
                    return handler.next(retryError);
                  } else {
                    return handler.next(e);
                  }
                }
                await Future.delayed(const Duration(seconds: 2));
              }
            }
          }

          return handler.next(e);
        },
      ),
    );
  }

  // 验证数据格式
  bool _validateData(Map<String, dynamic> data) {
    try {
      if (!data.containsKey('transactions')) {
        throw DataSyncException(
          '数据缺少transactions字段',
          DataSyncErrorType.dataValidationError,
        );
      }

      if (data['transactions'] is! List) {
        throw DataSyncException(
          'transactions字段不是列表格式',
          DataSyncErrorType.dataValidationError,
        );
      }

      // 如果transactions是空列表，直接返回true
      if ((data['transactions'] as List).isEmpty) {
        return true;
      }

      final transactions = data['transactions'] as List;
      for (var transaction in transactions) {
        if (transaction is! Map<String, dynamic>) {
          throw DataSyncException(
            '交易记录格式错误',
            DataSyncErrorType.dataValidationError,
          );
        }

        // 验证必要字段
        final requiredFields = ['id', 'amount', 'type', 'category', 'date'];
        for (var field in requiredFields) {
          if (!transaction.containsKey(field)) {
            throw DataSyncException(
              '交易记录缺少必要字段: $field',
              DataSyncErrorType.dataValidationError,
            );
          }
        }

        // 验证字段类型
        if (transaction['amount'] is! num) {
          throw DataSyncException(
            '金额字段类型错误',
            DataSyncErrorType.dataValidationError,
          );
        }

        if (transaction['date'] is! String) {
          throw DataSyncException(
            '日期字段类型错误',
            DataSyncErrorType.dataValidationError,
          );
        }
      }

      return true;
    } catch (e) {
      if (e is DataSyncException) {
        rethrow;
      }
      throw DataSyncException(
        '数据验证失败: ${e.toString()}',
        DataSyncErrorType.dataValidationError,
        e,
      );
    }
  }

  // 从GitHub获取数据
  Future<Map<String, dynamic>> fetchDataFromGitHub() async {
    try {
      // 检查网络连接
      final connectivityResult = await _connectivity.checkConnectivity();
      if (connectivityResult == ConnectivityResult.none) {
        throw DataSyncException('无网络连接', DataSyncErrorType.networkError);
      }

      final response = await _dio.get('$_baseUrl$_repoPath/transactions.json');
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is Map<String, dynamic> && data.containsKey('content')) {
          try {
            // 解码base64内容
            final content = data['content'] as String;
            final normalizedContent = content.replaceAll('\n', '');
            final decodedContent = utf8.decode(
              base64.decode(normalizedContent),
            );
            final jsonData = jsonDecode(decodedContent);

            if (jsonData is Map<String, dynamic>) {
              // 如果数据为空，返回空数据结构
              if (!jsonData.containsKey('transactions')) {
                return {
                  'transactions': [],
                  'lastSync': DateTime.now().toIso8601String(),
                };
              }

              // 验证数据格式
              try {
                _validateData(jsonData);
                return jsonData;
              } catch (e) {
                debugPrint('数据验证失败，返回空数据: $e');
                return {
                  'transactions': [],
                  'lastSync': DateTime.now().toIso8601String(),
                };
              }
            } else {
              debugPrint('下载的数据格式错误，返回空数据');
              return {
                'transactions': [],
                'lastSync': DateTime.now().toIso8601String(),
              };
            }
          } catch (e) {
            debugPrint('解码数据时出错: $e');
            return {
              'transactions': [],
              'lastSync': DateTime.now().toIso8601String(),
            };
          }
        } else {
          debugPrint('从GitHub获取数据时出错: 响应格式错误');
          return {
            'transactions': [],
            'lastSync': DateTime.now().toIso8601String(),
          };
        }
      } else {
        throw DataSyncException(
          '从GitHub获取数据时出错: ${response.statusCode}',
          DataSyncErrorType.serverError,
        );
      }
    } on DataSyncException {
      rethrow;
    } catch (e) {
      debugPrint('从GitHub获取数据时出错: $e');
      throw DataSyncException(
        '从GitHub获取数据时出错: ${e.toString()}',
        DataSyncErrorType.unknownError,
        e,
      );
    }
  }

  // 保存数据到本地
  Future<void> saveDataLocally(Map<String, dynamic> data) async {
    try {
      // 验证数据格式
      _validateData(data);

      await _prefs.setString('transactions', jsonEncode(data));
    } on DataSyncException {
      rethrow;
    } catch (e) {
      throw DataSyncException(
        '保存本地数据失败: ${e.toString()}',
        DataSyncErrorType.localStorageError,
        e,
      );
    }
  }

  // 从本地加载数据
  Map<String, dynamic>? loadLocalData() {
    try {
      final String? data = _prefs.getString('transactions');
      if (data != null) {
        final decoded = jsonDecode(data);
        if (decoded is Map<String, dynamic>) {
          // 验证数据格式
          _validateData(decoded);
          return decoded;
        }
      }
      return null;
    } on DataSyncException {
      rethrow;
    } catch (e) {
      throw DataSyncException(
        '加载本地数据失败: ${e.toString()}',
        DataSyncErrorType.localStorageError,
        e,
      );
    }
  }

  // 比较本地数据和GitHub数据
  Future<bool> compareData(Map<String, dynamic> localData) async {
    try {
      // 检查网络连接
      final connectivityResult = await _connectivity.checkConnectivity();
      if (connectivityResult == ConnectivityResult.none) {
        throw DataSyncException('无网络连接', DataSyncErrorType.networkError);
      }

      final githubData = await fetchDataFromGitHub();
      return mapEquals(localData, githubData);
    } on DataSyncException {
      rethrow;
    } catch (e) {
      throw DataSyncException(
        '比较数据失败: ${e.toString()}',
        DataSyncErrorType.unknownError,
        e,
      );
    }
  }

  // 恢复数据
  Future<Map<String, dynamic>> recoverData() async {
    try {
      final githubData = await fetchDataFromGitHub();
      await saveDataLocally(githubData);
      return githubData;
    } catch (e) {
      debugPrint('Error recovering data: $e');
      rethrow;
    }
  }

  // 测试数据同步
  Future<bool> testDataSync() async {
    try {
      final testData = {
        'test': 'data',
        'timestamp': DateTime.now().toIso8601String(),
      };

      // 保存测试数据
      await saveDataLocally(testData);

      // 从本地加载测试数据
      final loadedData = loadLocalData();
      if (loadedData == null) {
        return false;
      }

      // 验证数据完整性
      return mapEquals(testData, loadedData);
    } catch (e) {
      debugPrint('Error testing data sync: $e');
      return false;
    }
  }

  // 上传数据到 GitHub
  Future<void> uploadDataToGitHub(Map<String, dynamic> data) async {
    try {
      // 检查网络连接
      final connectivityResult = await _connectivity.checkConnectivity();
      if (connectivityResult == ConnectivityResult.none) {
        debugPrint('[uploadDataToGitHub] No network connection');
        throw DataSyncException('无网络连接', DataSyncErrorType.networkError);
      }

      // 验证数据格式
      _validateData(data);
      debugPrint('[uploadDataToGitHub] Data to upload: ${jsonEncode(data)}');

      // 获取当前文件的SHA
      String? sha;
      try {
        final response = await _dio.get(
          '$_baseUrl$_repoPath/transactions.json',
        );
        if (response.statusCode == 200 && response.data['sha'] != null) {
          sha = response.data['sha'];
          debugPrint('[uploadDataToGitHub] Got file SHA: $sha');
        } else {
          debugPrint('[uploadDataToGitHub] Failed to get file SHA');
          throw DataSyncException('无法获取文件SHA', DataSyncErrorType.serverError);
        }
      } catch (e) {
        debugPrint('[uploadDataToGitHub] Error getting file SHA: $e');
        throw DataSyncException(
          '获取文件SHA失败: ${e.toString()}',
          DataSyncErrorType.serverError,
          e,
        );
      }

      // 准备请求体
      final body = {
        'message': 'Update transactions data',
        'content': base64Encode(utf8.encode(jsonEncode(data))),
        'sha': sha, // SHA 现在是必须的
      };
      debugPrint('[uploadDataToGitHub] Request body: ${jsonEncode(body)}');

      // 上传数据
      final response = await _dio.put(
        '$_baseUrl$_repoPath/transactions.json',
        data: jsonEncode(body),
      );
      debugPrint(
        '[uploadDataToGitHub] Server response: ${response.statusCode} - ${response.data}',
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        debugPrint('[uploadDataToGitHub] Data upload successful');
        await saveDataLocally(data);
        return;
      }

      debugPrint(
        '[uploadDataToGitHub] Data upload failed: HTTP ${response.statusCode}',
      );
      throw DataSyncException(
        '上传数据失败: HTTP ${response.statusCode}',
        DataSyncErrorType.serverError,
      );
    } on DataSyncException {
      rethrow;
    } catch (e) {
      debugPrint('[uploadDataToGitHub] Error uploading data: $e');
      throw DataSyncException(
        '上传数据失败: ${e.toString()}',
        DataSyncErrorType.unknownError,
        e,
      );
    }
  }

  // 加载测试数据
  Future<void> loadTestData() async {
    try {
      final testData = {
        'transactions': [
          {
            'id': '1',
            'title': '午餐',
            'amount': 25.5,
            'date': '2024-03-19T12:00:00.000Z',
            'type': 'expense',
            'category': 'food',
            'note': '公司食堂',
            'currency': 'CNY',
            'created_at': 1710835200000,
            'updated_at': 1710835200000,
          },
          {
            'id': '2',
            'title': '工资',
            'amount': 8000,
            'date': '2024-03-15T09:00:00.000Z',
            'type': 'income',
            'category': 'salary',
            'note': '3月工资',
            'currency': 'CNY',
            'created_at': 1710489600000,
            'updated_at': 1710489600000,
          },
          {
            'id': '3',
            'title': '电影票',
            'amount': 45,
            'date': '2024-03-18T19:30:00.000Z',
            'type': 'expense',
            'category': 'entertainment',
            'note': '周末电影',
            'currency': 'CNY',
            'created_at': 1710748800000,
            'updated_at': 1710748800000,
          },
          {
            'id': '4',
            'title': '交通卡充值',
            'amount': 100,
            'date': '2024-03-17T08:00:00.000Z',
            'type': 'expense',
            'category': 'transportation',
            'note': '地铁卡充值',
            'currency': 'CNY',
            'created_at': 1710662400000,
            'updated_at': 1710662400000,
          },
          {
            'id': '5',
            'title': '生日礼物',
            'amount': 200,
            'date': '2024-03-16T14:00:00.000Z',
            'type': 'expense',
            'category': 'gift',
            'note': '朋友生日礼物',
            'currency': 'CNY',
            'created_at': 1710576000000,
            'updated_at': 1710576000000,
          },
        ],
        'lastSync': DateTime.now().toIso8601String(),
      };

      // 保存到本地
      await saveDataLocally(testData);

      // 上传到GitHub
      await uploadDataToGitHub(testData);

      debugPrint('测试数据加载成功');
    } catch (e) {
      debugPrint('加载测试数据失败: $e');
      rethrow;
    }
  }
}
